package juc.topic;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 两个线程交替打印ABCD..Z字母，一个大写一个小写
 * 目标输出：AbCdEfGhIjKlMnOpQrStUvWxYz
 * 使用ReentrantLock实现线程间的同步和条件变量的等待/通知机制
 */
public class AlternateLetterPrinting02 {

    // 标记当前线程是否应该打印大写字母
    private static boolean printUpperCase = true;
    // 当前要打印的字母，从'A'开始
    private static char letter = 'A';

    // 创建一个可重入锁对象，用于控制对共享资源的访问
    private static final Lock lock = new ReentrantLock();
    // 用于控制小写字母打印线程的条件变量
    private static final Condition printLowCondition = lock.newCondition();
    // 用于控制大写字母打印线程的条件变量
    private static final Condition printUpCondition = lock.newCondition();

    /**
     * 主方法，启动两个线程分别打印大写和小写字母
     * @param args 命令行参数
     */
    public static void main(String[] args) {
        AlternateLetterPrinting02 printing02 = new AlternateLetterPrinting02();

        // 启动大写字母打印线程
        new Thread(() -> {
            try {
                printing02.printLetter(true);
            } catch (InterruptedException e) {
                // 如果线程被中断，重新设置中断状态并抛出运行时异常
                Thread.currentThread().interrupt();
                throw new RuntimeException(e);
            }
        }, "大写字母").start();

        // 启动小写字母打印线程
        new Thread(() -> {
            try {
                printing02.printLetter(false);
            } catch (InterruptedException e) {
                // 如果线程被中断，重新设置中断状态并抛出运行时异常
                Thread.currentThread().interrupt();
                throw new RuntimeException(e);
            }
        }, "小写字母").start();
    }

    /**
     * 打印字母的方法，根据isUpLetter参数决定打印大写还是小写字母
     * @param isUpLetter true表示打印大写字母，false表示打印小写字母
     * @throws InterruptedException 如果线程在等待条件时被中断
     */
    public void printLetter(boolean isUpLetter) throws InterruptedException {
        while (letter <= 'Z') {
            lock.lock(); // 加锁，确保线程安全
            try {
                // 如果当前线程不应该打印当前类型的字母，则等待
                while (printUpperCase != isUpLetter) {
                    if (isUpLetter) {
                        printUpCondition.await(); // 大写字母线程等待
                    } else {
                        printLowCondition.await(); // 小写字母线程等待
                    }
                }

                // 打印当前字母
                if (isUpLetter) {
                    System.out.print(letter);
                } else {
                    System.out.print(Character.toLowerCase(letter));
                }

                // 更新字母到下一个
                letter++;

                // 切换打印类型（大写或小写）
                printUpperCase = !printUpperCase;

                // 通知另一个线程可以继续打印
                if (isUpLetter) {
                    printLowCondition.signal(); // 通知小写字母线程
                } else {
                    printUpCondition.signal(); // 通知大写字母线程
                }
            } finally {
                lock.unlock(); // 解锁
            }
        }
    }
}